<template>
  <div class="prediction-analysis-container">
    <div class="page-header">
      <h2>预测与误差分析</h2>
      <div class="filter-controls">
        <el-select v-model="selectedModel" placeholder="选择模型" size="default" class="mr-10">
          <el-option label="Transformer v1.0" value="transformer_v1"></el-option>
          <el-option label="LSTM v2.1" value="lstm_v2"></el-option>
          <el-option label="XGBoost v1.5" value="xgboost_v1"></el-option>
          <el-option label="Fully Connected Network v1.0" value="fully_connected_network_v1"></el-option>
        </el-select>
        <el-date-picker v-model="dateRange" type="datetimerange" range-separator="至" start-placeholder="开始日期时间"
          end-placeholder="结束日期时间" size="default"></el-date-picker>
        <el-button type="primary" :icon="Search" class="ml-10">查询</el-button>
      </div>
    </div>

    <el-row :gutter="20" class="metric-cards">
      <el-col :span="6">
        <el-card class="metric-card">
          <div class="card-content">
            <span class="metric-label">平均绝对误差 (MAE)</span>
            <span class="metric-value">{{ evaluationData[0]?.value }}</span>
            <div class="metric-trend">
              <el-icon class="trend-icon success">
                <CaretTop />
              </el-icon>
              <span>+2.5% (昨日)</span>
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="metric-card">
          <div class="card-content">
            <span class="metric-label">均方根误差 (RMSE)</span>
            <span class="metric-value">{{ evaluationData[1]?.value }}</span>
            <div class="metric-trend">
              <el-icon class="trend-icon danger">
                <CaretBottom />
              </el-icon>
              <span>-1.2% (昨日)</span>
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="metric-card">
          <div class="card-content">
            <span class="metric-label">平均绝对百分比误差 (MAPE)</span>
            <span class="metric-value">{{ evaluationData[2]?.value }}</span>
            <div class="metric-trend">
              <el-icon class="trend-icon info">
                <Minus />
              </el-icon>
              <span>0% (昨日)</span>
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card class="metric-card">
          <div class="card-content">
            <span class="metric-label">R² 分数</span>
            <span class="metric-value">{{ evaluationData[3]?.value }}</span>
            <div class="metric-trend">
              <el-icon class="trend-icon success">
                <CaretTop />
              </el-icon>
              <span>+0.01 (昨日)</span>
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <el-card class="chart-card mb-20">
      <h3>实际值与预测值对比</h3>
      <div id="prediction-vs-actual-chart" style="width: 100%; height: 350px;"></div>
    </el-card>

    <el-card class="chart-card mb-20">
      <h3>预测误差分布</h3>
      <div id="error-distribution-chart" style="width: 100%; height: 300px;"></div>
    </el-card>

    <el-card class="table-card">
      <h3>模型详细评估指标</h3>
      <el-table :data="evaluationData" style="width: 100%" border>
        <el-table-column prop="metric" label="评估指标" width="180"></el-table-column>
        <el-table-column prop="value" label="值"></el-table-column>
        <el-table-column prop="description" label="描述"></el-table-column>
      </el-table>
    </el-card>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, watch } from 'vue';
import * as echarts from 'echarts';
import { Search, CaretTop, CaretBottom, Minus } from '@element-plus/icons-vue';

// 选中的模型
const selectedModel = ref('transformer_v1');
const dateRange = ref([]);

// 多模型数据结构，初始为空
const modelDataMap = ref({
  transformer_v1: { time_points: [], predicted_values: [], true_values: [] },
  lstm_v2: { time_points: [], predicted_values: [], true_values: [] },
  xgboost_v1: { time_points: [], predicted_values: [], true_values: [] },
  fully_connected_network_v1: { time_points: [], predicted_values: [], true_values: [] }
});

// 动态加载 transformer 数据
const loadTransformerData = async () => {
  const res = await fetch('/load_forecast_5days.json');
  const json = await res.json();
  modelDataMap.value.transformer_v1.time_points = json.time_hours || [];
  modelDataMap.value.transformer_v1.predicted_values = json.predicted_load || [];
  modelDataMap.value.transformer_v1.true_values = json.actual_load || [];
};

// 动态加载 lstm 数据
const loadLstmData = async () => {
  const res = await fetch('/plot_data_index_6000.json');
  const json = await res.json();
  modelDataMap.value.lstm_v2.time_points = json.time_points || [];
  modelDataMap.value.lstm_v2.predicted_values = json.predicted_values || [];
  modelDataMap.value.lstm_v2.true_values = json.true_values || [];
};

// 动态加载 xgboost 数据
const loadXgboostData = async () => {
  const res = await fetch('/xgboost_prediction_output.json');
  const json = await res.json();
  modelDataMap.value.xgboost_v1.time_points = json.time_points || [];
  modelDataMap.value.xgboost_v1.predicted_values = json.predicted_values || [];
  modelDataMap.value.xgboost_v1.true_values = json.actual_values || [];
  console.log('time_points:', json.time_points.length);
  console.log('actual_values:', json.actual_values.length);
  console.log('predicted_values:', json.predicted_values.length);
  console.log('actual_values:', json.actual_values);
  console.log('predicted_values:', json.predicted_values);
};

// 动态加载全连接神经网络数据
const loadFnnData = async () => {
  const res = await fetch('/training_sample_output.json');
  const json = await res.json();
  modelDataMap.value.fully_connected_network_v1.time_points = json.time_points || [];
  modelDataMap.value.fully_connected_network_v1.predicted_values = json.predicted_values || [];
  modelDataMap.value.fully_connected_network_v1.true_values = json.true_values || [];
};

onMounted(() => {
  loadTransformerData();
  loadLstmData();
  loadXgboostData();
  loadFnnData();
});

// 计算当前模型的数据
const currentModelData = computed(() => modelDataMap.value[selectedModel.value] || {});

// 构造 x 轴时间标签
const timestamps = computed(() => {
  const tp = currentModelData.value.time_points || [];
  // Transformer/LSTM/XGBoost/全连接神经网络的时间格式可能不同
  if (selectedModel.value === 'transformer_v1' || selectedModel.value === 'lstm_v2') {
    // 如果是数字小时，显示“第N天N时”
    return tp.map(t => {
      const day = Math.floor(t / 24) + 1;
      const hour = Math.floor(t % 24);
      return `第${day}天${hour}时`;
    });
  } else if (selectedModel.value === 'xgboost_v1' || selectedModel.value === 'fully_connected_network_v1') {
    // 如果是字符串时间，直接显示
    if (tp.length && typeof tp[0] === 'string') {
      return tp;
    }
    // 如果是数字小时，显示“第N点”
    return tp.map((_, i) => `第${i + 1}点`);
  }
  // 默认直接显示索引
  return tp.map((_, i) => i + 1);
});

// 预测与实际数据
const predictionData = computed(() => ({
  timestamps: timestamps.value,
  actual: currentModelData.value.true_values || [],
  predicted: currentModelData.value.predicted_values || []
}));

// 误差分布
const errorArr = computed(() =>
  (currentModelData.value.predicted_values || []).map(
    (v, i) => v - (currentModelData.value.true_values?.[i] ?? 0)
  )
);
const errorDistributionData = computed(() => [
  { value: errorArr.value.filter(e => e <= -200).length, name: '(-∞, -200]' },
  { value: errorArr.value.filter(e => e > -200 && e <= -100).length, name: '(-200, -100]' },
  { value: errorArr.value.filter(e => e > -100 && e <= -50).length, name: '(-100, -50]' },
  { value: errorArr.value.filter(e => e > -50 && e <= 0).length, name: '(-50, 0]' },
  { value: errorArr.value.filter(e => e > 0 && e <= 50).length, name: '(0, 50]' },
  { value: errorArr.value.filter(e => e > 50 && e <= 100).length, name: '(50, 100]' },
  { value: errorArr.value.filter(e => e > 100 && e <= 200).length, name: '(100, 200]' },
  { value: errorArr.value.filter(e => e > 200).length, name: '(200, +∞)' }
]);

// 评估指标
const evaluationData = computed(() => {
  const err = errorArr.value;
  const trueVals = currentModelData.value.true_values || [];
  if (!err.length || !trueVals.length) return [];
  const mae = (err.reduce((a, b) => a + Math.abs(b), 0) / err.length).toFixed(2) + ' kW';
  const rmse = Math.sqrt(err.reduce((a, b) => a + b * b, 0) / err.length).toFixed(2) + ' kW';
  const mape = (err.reduce((a, b, i) => a + Math.abs(b / (trueVals[i] || 1)), 0) / err.length * 100).toFixed(2) + ' %';
  const mean = trueVals.reduce((a, b) => a + b, 0) / trueVals.length;
  const ssTot = trueVals.reduce((a, b) => a + Math.pow(b - mean, 2), 0);
  const ssRes = err.reduce((a, b) => a + b * b, 0);
  const r2 = (1 - ssRes / ssTot).toFixed(4);
  const mse = (err.reduce((a, b) => a + b * b, 0) / err.length).toFixed(2);
  return [
    { metric: 'MAE', value: mae, description: '平均绝对误差' },
    { metric: 'RMSE', value: rmse, description: '均方根误差' },
    { metric: 'MAPE', value: mape, description: '平均绝对百分比误差' },
    { metric: 'R²', value: r2, description: '决定系数' },
    { metric: 'MSE', value: mse, description: '均方误差' }
  ];
});

// ECharts 初始化函数
const initPredictionVsActualChart = () => {
  const chartDom = document.getElementById('prediction-vs-actual-chart');
  if (chartDom) {
    const myChart = echarts.init(chartDom);

    // 合并所有数据，计算y轴范围
    const allValues = [
      ...(predictionData.value.actual || []),
      ...(predictionData.value.predicted || [])
    ].filter(v => typeof v === 'number' && !isNaN(v));
    let minY = allValues.length ? Math.min(...allValues) : 0;
    let maxY = allValues.length ? Math.max(...allValues) : 1;
    if (minY === maxY) {
      minY = minY * 0.95;
      maxY = maxY * 1.05;
    } else {
      const padding = (maxY - minY) * 0.1;
      minY = Math.floor(minY - padding);
      maxY = Math.ceil(maxY + padding);
    }

    const option = {
      tooltip: { trigger: 'axis' },
      legend: { data: ['实际值', '预测值'] },
      grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
      xAxis: {
        type: 'category',
        boundaryGap: false,
        data: predictionData.value.timestamps
      },
      yAxis: {
        type: 'value',
        name: '负荷 (kW)',
        min: minY,
        max: maxY
      },
      series: [
        {
          name: '实际值',
          type: 'line',
          smooth: true,
          symbol: 'circle',
          symbolSize: 4, // 更小的点
          lineStyle: { width: 2 }, // 细线条
          areaStyle: { opacity: 0.08 },
          emphasis: { focus: 'series' },
          data: predictionData.value.actual,
          itemStyle: { color: '#5470C6' }
        },
        {
          name: '预测值',
          type: 'line',
          smooth: true,
          symbol: 'circle',
          symbolSize: 4, // 更小的点
          lineStyle: { width: 2 }, // 细线条
          areaStyle: { opacity: 0.08 },
          emphasis: { focus: 'series' },
          data: predictionData.value.predicted,
          itemStyle: { color: '#91CC75' }
        }
      ]
    };
    myChart.setOption(option);
    window.addEventListener('resize', () => myChart.resize());
  }
};

const initErrorDistributionChart = () => {
  const chartDom = document.getElementById('error-distribution-chart');
  if (chartDom) {
    const myChart = echarts.init(chartDom);
    const option = {
      tooltip: {
        trigger: 'axis',
        axisPointer: {
          type: 'shadow'
        }
      },
      grid: {
        left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true
      },
      xAxis: {
        type: 'category',
        data: errorDistributionData.value.map(item => item.name),
        axisTick: {
          alignWithLabel: true
        }
      },
      yAxis: {
        type: 'value',
        name: '数量'
      },
      series: [
        {
          name: '误差数量',
          type: 'bar',
          barWidth: '60%',
          data: errorDistributionData.value.map(item => item.value),
          itemStyle: {
            color: new echarts.graphic.LinearGradient(
              0, 0, 0, 1, // 渐变方向，从上到下
              [
                { offset: 0, color: '#5470C6' }, // 渐变开始颜色 (蓝色)
                { offset: 1, color: '#91CC75' } // 渐变结束颜色 (绿色)
              ]
            )
          },
          emphasis: {
            itemStyle: {
              color: new echarts.graphic.LinearGradient(
                0, 0, 0, 1,
                [
                  { offset: 0, color: '#91CC75' },
                  { offset: 1, color: '#5470C6' }
                ]
              )
            }
          }
        }
      ]
    };
    myChart.setOption(option);
    window.addEventListener('resize', () => myChart.resize());
  }
};

// mounted 钩子中初始化图表
onMounted(() => {
  initPredictionVsActualChart();
  initErrorDistributionChart();
});

// 监听数据变化，如果数据是异步加载的，可以在这里重新渲染图表
watch([predictionData, errorDistributionData], () => {
  initPredictionVsActualChart();
  initErrorDistributionChart();
}, { deep: true });

</script>

<style lang="scss" scoped>
// SCSS 变量直接定义在这里
$primary-blue: #409eff; // Element Plus 主题蓝
$dark-blue: #2a7cff; // 更深的蓝色，用于渐变或阴影
$light-blue: #e6f7ff; // 浅蓝色，用于背景或点缀
$text-dark: #303133; // 深色文字
$text-light: #606266; // 浅色文字
$bg-light-gray: #f7f9fc; // 页面背景色，比 #f0f2f5 更柔和

.prediction-analysis-container {
  padding: 20px;
  background-color: $bg-light-gray;
  min-height: calc(100vh - 100px); // 减去header和tab的高度，保证背景完整
  border-radius: 8px; // 保持卡片外的圆角
  box-sizing: border-box; // 确保padding不增加总宽度/高度

  h2 {
    font-size: 1.8em;
    color: $text-dark;
    margin-bottom: 20px;
  }

  .mr-10 {
    margin-right: 10px;
  }

  .ml-10 {
    margin-left: 10px;
  }

  .mb-20 {
    margin-bottom: 20px;
  }

  .page-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
    padding: 15px 20px;
    background-color: #ffffff;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  }

  .filter-controls {
    display: flex;
    align-items: center;

    .el-select,
    .el-date-picker {
      width: 220px; // 调整选择器宽度
    }
  }

  .metric-cards {
    margin-bottom: 20px;

    .metric-card {
      border-radius: 10px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
      border-left: 5px solid $primary-blue; // 左侧边框
      // background: linear-gradient(45deg, #ffffff, $light-blue); // 轻微渐变背景，如果需要可以取消注释

      .card-content {
        display: flex;
        flex-direction: column;
        align-items: flex-start; // 左对齐
        padding: 10px 0;
      }

      .metric-label {
        font-size: 0.9em;
        color: $text-light;
        margin-bottom: 5px;
      }

      .metric-value {
        font-size: 1.8em;
        font-weight: bold;
        color: $text-dark;
        margin-bottom: 5px;
      }

      .metric-trend {
        display: flex;
        align-items: center;
        font-size: 0.8em;
        color: $text-light;

        .trend-icon {
          margin-right: 5px;

          &.success {
            color: #67c23a;
          }

          // 绿色
          &.danger {
            color: #f56c6c;
          }

          // 红色
          &.info {
            color: #909399;
          }

          // 灰色
        }
      }
    }
  }

  .chart-card,
  .table-card {
    border-radius: 10px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
    padding: 20px; // 增加内边距
    background-color: #ffffff;

    h3 {
      font-size: 1.3em;
      color: $text-dark;
      margin-bottom: 20px;
      border-bottom: 1px solid #ebeef5; // 分隔线
      padding-bottom: 10px;
    }
  }

  .el-table {
    .el-table__header-wrapper th {
      background-color: #f5f7fa; // 表头背景色
      color: $text-dark;
    }

    .el-table__body-wrapper td {
      color: $text-light;
    }
  }
}
</style>